#ifndef __NFA__

#define __NFA__

#include<iostream>
#include <map>
#include <string>
#include <cstdlib>
#include<set>
#include"fa.h"
#include"namestorage.h"
#include"dfa.h"

class NFA : public FA {

	mutable std::set<unsigned> starting;
	mutable std::set<unsigned> accepting;
	mutable std::multimap<std::pair<unsigned, char>, unsigned> rules;
	bool epsilonFree;
	
	std::set<unsigned> epsilonExpand(std::set<unsigned> const &) const;
	void renameStates(unsigned, unsigned) const;
	void renameStates(std::map<unsigned, unsigned> const &) const;
	void resolveConflict(std::set<unsigned>) const;
	void duplicateLinks(unsigned, unsigned);
	bool ruleExists(std::pair<unsigned, char> const &, unsigned) const;
	
	
	//static NameStorage initNames();
	//static pair<pair<unsigned, char>, unsigned> get_rule_from_stream(std::istream&);
	//static string extractAlNum(string const &);

public:
	
	NFA() : epsilonFree(true) {}
	~NFA() {}

	friend std::istream & operator>> (std::istream &, NFA &);
	std::set<unsigned> const & startingState() const;
	std::set<unsigned> const & acceptingStates() const;
	std::set<unsigned> feedTerminal(unsigned, char) const;
	std::set<unsigned> feedTerminal(std::set<unsigned> const &, char) const;
	std::set<unsigned> feedAnyOfThe(std::set<unsigned> const &, std::set<char> const &) const;
	std::set<unsigned> feedString(unsigned, std::string const &) const;
	std::set<unsigned> feedString(std::set<unsigned> const &, std::string const &) const;
	friend std::ostream & operator<< (std::ostream &, NFA const &);
	bool isAccepting(unsigned) const;
	bool isAccepting(std::set<unsigned> const &) const;
	std::set<unsigned> allStates() const;
	std::set<unsigned> reachableStates() const;
	std::set<char> apparentAlphabet() const;
	void eliminateEpsilon();
	DFA determinate() const;
		
	NFA & operator= (NFA const &);
	NFA & operator|= (NFA const &);
	NFA & operator&= (NFA const &);
	NFA & operator+= (NFA const &);
	bool operator== (NFA const &) const;
	NFA operator! () const;
	NFA operator| (NFA const &) const;
	NFA operator& (NFA const &) const;
	NFA operator+ (NFA const &) const;
	NFA operator* () const;
	
	friend int main();
};


#endif
